package com.jackrain.nea.web.controller;

import com.alibaba.dubbo.common.URL;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.jackrain.nea.config.Resources;
import com.jackrain.nea.constants.LoginAliveTimeLevel;
import com.jackrain.nea.dao.LoginInfoReposity;
import com.jackrain.nea.shiro.stateful.CachingShiroSessionDao;
import com.jackrain.nea.shiro.stateful.LoginType;
import com.jackrain.nea.util.ShiroSessionUtil;
import com.jackrain.nea.util.TryLoginUtil;
import com.jackrain.nea.util.ValueHolder;
import com.jackrain.nea.util.WebUtils;
import com.jackrain.nea.web.face.User;
import com.jackrain.nea.web.face.impl.UserImpl;
import com.jackrain.nea.web.permisssion.PermissionLoader;
import com.jackrain.nea.web.query.QuerySession;
import com.jackrain.nea.web.query.QuerySessionImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import static org.apache.shiro.SecurityUtils.getSubject;

/**
 * Created by nathan on 2016/7/27.
 */

@RestController
@Api(value = "登录")
public class LoginController {

    public final Logger logger = Logger.getLogger(LoginController.class);

    private TryLoginUtil tryLoginUtil = new TryLoginUtil();

    @Autowired
    private LoginInfoReposity loginInfoReposity;

    @Autowired
    private CachingShiroSessionDao sessionDao;

    /**
     * 登录检验
     *
     * @return
     */
    @ApiOperation(value = "登录检验")
    @RequestMapping(path = "/p/c/rememberMeLogin", method = RequestMethod.GET)
    public JSONObject rememberMeLogin() {
        Subject subject = getSubject();
        ValueHolder valueHolder = new ValueHolder();
        if (subject != null && (subject.isAuthenticated() || subject.isRemembered())) {
            ShiroSessionUtil.isLogin();
            valueHolder.put("user", subject.getPrincipal());
            valueHolder.put("code", 1);
        } else {
            valueHolder.put("message", Resources.getMessage("login-rememberMe-fail"));
            valueHolder.put("code", -1);
        }
        return valueHolder.toJSONObject();
    }


    /**
     * 登录方法
     *
     * @param request
     * @param response
     * @param session
     * @return
     */
    @ApiOperation(value = "登录")
    @RequestMapping(path = "/p/c/login", method = {RequestMethod.GET, RequestMethod.POST})
    public JSONObject login(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
        ValueHolder valueHolder = new ValueHolder();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String captcha = request.getParameter("captcha");
        Boolean rememberMe = Boolean.valueOf(request.getParameter("rememberMe"));
        Subject subject = SecurityUtils.getSubject();
        String IP = WebUtils.getIpAddress(request);//获取客户端IP
        WebUtils webUtils = new WebUtils();

        if (StringUtils.isEmpty(captcha)){
            valueHolder.put("code",-1);
            valueHolder.put("msg","captcha is null");
            return valueHolder.toJSONObject();
        }
        //验证
        boolean gtResult = webUtils.verCaptcha(captcha);
        if (!gtResult){
            valueHolder.put("code",-1);
            valueHolder.put("msg",Resources.getMessage("Verification_code_error"));
            return valueHolder.toJSONObject();
        }

        if (tryLoginUtil.tryLogin(username, password, LoginType.WITH_PASSWORD, rememberMe, subject, IP)) {
            //加载下权限
            User userWeb = (UserImpl) request.getSession().getAttribute("user");
            QuerySession qSession = new QuerySessionImpl(userWeb);
            PermissionLoader.load(qSession);
            valueHolder.put("user", subject.getPrincipal());
            valueHolder.put("code", 1);
        } else {
            String message = "";
            ValueHolder vh = (ValueHolder) ShiroSessionUtil.getAttribute("vh");
            if (vh != null && !"".equals(vh)) {
                message = (String) vh.get("message");
            }
            valueHolder.put("code", -1);
            valueHolder.put("msg", message);
            return valueHolder.toJSONObject();
        }
        return valueHolder.toJSONObject();
    }


    /**
     * 登录方法
     *
     * @param request
     * @param response
     * @param session
     * @return
     */
    @ApiOperation(value = "第三方登录")
    @RequestMapping(path = "/p/c/thirdlogin", method = {RequestMethod.GET, RequestMethod.POST})
    public JSONObject thirdLogin(HttpServletRequest request, HttpServletResponse response, HttpSession session,@RequestParam(value = "url",required = false)String url) {
        ValueHolder valueHolder = new ValueHolder();
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        Boolean rememberMe = Boolean.valueOf(request.getParameter("rememberMe"));
        Subject subject = SecurityUtils.getSubject();
        String IP = WebUtils.getIpAddress(request);//获取客户端IP

        if (tryLoginUtil.tryLogin(username, password, LoginType.NO_PASSWORD, rememberMe, subject, IP)) {
            //加载下权限
            User userWeb = (UserImpl) request.getSession().getAttribute("user");
            QuerySession qSession = new QuerySessionImpl(userWeb);
            PermissionLoader.load(qSession);

            valueHolder.put("user", subject.getPrincipal());
            valueHolder.put("code", 1);
            if(StringUtils.isNotBlank(url)) {
                try {
                    response.sendRedirect(response.encodeRedirectURL(url));
                } catch (IOException e) {
                    logger.error(e.getMessage(),e);
                }
            }
        } else {
            String message = "";
            ValueHolder vh = (ValueHolder) ShiroSessionUtil.getAttribute("vh");
            if (vh != null && !"".equals(vh)) {
                message = (String) vh.get("message");
            }
            valueHolder.put("code", -1);
            valueHolder.put("msg", message);
            return valueHolder.toJSONObject();
        }
        return valueHolder.toJSONObject();
    }


    @RequestMapping(path = "/p/cs/logout", method = RequestMethod.GET)
    public JSONObject logout(HttpServletRequest request, HttpServletResponse response) throws IOException {

        Cookie[] cookies = request.getCookies();
        for (int i = 0; i < cookies.length; i++) {
            Cookie v = cookies[i];
            if (v.getName().equals("verificationSafe")) {
                v.setMaxAge(0);
                response.addCookie(v);
            }
        }
        Subject subject = getSubject();
        User user = (User) subject.getPrincipal();
        subject.logout();
        ValueHolder valueHolder = new ValueHolder();
        valueHolder.put("code", 0);
        tryLoginUtil.logLogin(user, WebUtils.getIpAddress(request), request.getHeader("User-Agent"), request, "logout");

        return valueHolder.toJSONObject();
    }

    @RequestMapping(path = "/p/cs/touch", method = RequestMethod.GET)
    public void touch() {
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.touch();
    }


    @RequestMapping(path = "/p/cs/loginusers", method = RequestMethod.GET)
    public JSONObject queryLoginUsers(@RequestParam(value = "userName", required = false) String userName, @RequestParam(value = "pageSize", required = false) Integer pageSize,
                                      @RequestParam(value = "pageIndex", required = false) Integer pageIndex,@RequestParam(value = "startTime",required = false)String startTime,
                                      @RequestParam(value = "endTime",required = false)String endTime,@RequestParam(value = "aliveTime",required = false)Integer aliveTimeLevel) {
        ValueHolder valueHolder = new ValueHolder();
        pageSize = (pageSize == null || pageSize == 0) ? 10 : pageSize;
        pageIndex = pageIndex == null ? 0 : pageIndex;

        valueHolder.put("code", 0);

        LoginAliveTimeLevel level = null;
        if (aliveTimeLevel !=null && LoginAliveTimeLevel.values().length > aliveTimeLevel){
            level = LoginAliveTimeLevel.values()[aliveTimeLevel];
        }

        Page<JSONObject> loginUsers = loginInfoReposity.queryList(null, userName, pageSize, pageIndex,startTime,endTime,level);

        valueHolder.put("datas", loginUsers);
        return valueHolder.toJSONObject();
    }

    @RequestMapping(path = "/p/cs/kickout", method = {RequestMethod.GET,RequestMethod.POST})
    public JSONObject kickUsers(HttpServletRequest request, @RequestParam(value = "ids", required = false) String ids) {
        List<String> names = Lists.newArrayList();

        ValueHolder valueHolder = new ValueHolder();
        valueHolder.put("code", 0);
        if (StringUtils.isBlank(ids)) {
            valueHolder.put("code", -1);
            valueHolder.put("message","选择的用户不能为空");
            return valueHolder.toJSONObject();
        }
        User current = (User) SecurityUtils.getSubject().getPrincipal();
        int count = 0;
        List<String> failures = Lists.newArrayList();
        for (String id : ids.split(",")) {
            count++;
            Session session = sessionDao.readSession((Serializable) id);

            if (session != null) {
                try {
                    sessionDao.delete(session);
                    User user = (User) session.getAttribute("user");
                    if (user != null) {
                        names.add(user.getName());
                    }
                }catch (Exception e){
                    failures.add(id);
                }
            }else{
                failures.add(id);
            }
        }

        valueHolder.put("message",Resources.getMessage(String.format("需要清退%d个用户，其中%d个清退失败",count,failures.size())));
        valueHolder.put("data",failures);
        tryLoginUtil.logLogin(current, WebUtils.getIpAddress(request), String.join(",", names), request, "kickout");

        return valueHolder.toJSONObject();
    }

    @RequestMapping(path = "/p/cs/kickall", method = RequestMethod.GET)
    public JSONObject kickAllUsers(HttpServletRequest request) {
        ValueHolder valueHolder = new ValueHolder();
        valueHolder.put("code", 0);

        User current = (User) SecurityUtils.getSubject().getPrincipal();

        Collection<Session> sessions = sessionDao.getActiveSessions();

        List<String> failures = sessions.stream().parallel().map((session)->{
            try{sessionDao.delete(session);}catch (Exception e){return session.getId().toString();}return null;
        }).collect(Collectors.toList());

        valueHolder.put("message",Resources.getMessage(String.format("需要清退%d个用户，其中%d个清退失败",sessions.size(),failures.size())));
        valueHolder.put("data",failures);

        tryLoginUtil.logLogin(current, WebUtils.getIpAddress(request), request.getHeader("User-Agent"), request, "kickall");

        return valueHolder.toJSONObject();
    }

    @RequestMapping(path = "/p/cs/countUsers", method = RequestMethod.GET)
    public JSONObject countCurrentUsers() {
        ValueHolder valueHolder = new ValueHolder();
        valueHolder.put("code", 0);

        long count = sessionDao.getActiveSessions().stream().parallel()
                .filter((session) -> session.getAttribute("user") != null)
                .count();

        valueHolder.put("data",count);

        return valueHolder.toJSONObject();
    }


}
